#include "Signaling.h"
#include <QWebSocket>
#include <QDebug>
#include <QNetworkRequest>
#include <QSslConfiguration>
#include <QJsonDocument>
#include "PublicFunHelper.h"


Signaling::Signaling(QObject *parent) : QObject(parent)
{
    m_pWebSocket = NULL;
    m_seeionID = 0;
}

Signaling::~Signaling()
{
    QJsonObject destroyOby;
    destroyOby["janus"] = "destroy";
    this->sendMsg(destroyOby);

    if (m_pWebSocket->state() != QAbstractSocket::SocketState::UnconnectedState)
    {
        m_pWebSocket->close();
    }
}


void Signaling::init()
{
    if(m_pWebSocket == nullptr)
    {
        m_pWebSocket = new QWebSocket;
        m_pWebSocket->setParent(this);

        bool bOk = connect(m_pWebSocket, &QWebSocket::connected,
                           this, &Signaling::slotConnected);
        Q_ASSERT(bOk);

        bOk = connect(m_pWebSocket, &QWebSocket::disconnected,
                      this, &Signaling::slotDisConnected);

        bOk = connect(m_pWebSocket, SIGNAL(error(QAbstractSocket::SocketError)),
                      this, SLOT(slotError(QAbstractSocket::SocketError)));
        Q_ASSERT(bOk);

        bOk = connect(m_pWebSocket, &QWebSocket::textMessageReceived,
                      this, &Signaling::slotTextMessageReceived);
        Q_ASSERT(bOk);
    }
}

void Signaling::connectToServer(const QString &strServer)
{
    if(m_pWebSocket == nullptr)
    {
        init();
    }

    QNetworkRequest request(strServer);
    request.setRawHeader("Sec-WebSocket-Protocol", "janus-protocol");

    if(strServer.startsWith("wss://"))
    {
        QSslConfiguration config = QSslConfiguration::defaultConfiguration();
        config.setPeerVerifyMode(QSslSocket::VerifyNone);
        request.setSslConfiguration(config);
    }

    m_pWebSocket->open(request);
}

QString Signaling::doSendMsg(QJsonObject &msg)
{
    QString strTran = PublicFunHelper::getRandomString(12);
    msg[KEY_TRANSACTION] = strTran;
    if(m_seeionID != 0)
    {
        msg["session_id"] = m_seeionID;
    }
    qDebug() << __func__ << msg;
    QString strMsg = PublicFunHelper::convertToString(msg);
    m_pWebSocket->sendTextMessage(strMsg);

    return strTran;
}

void Signaling::sendMsg(QJsonObject &msg)
{
   doSendMsg(msg);
}

void Signaling::sendMsg(QJsonObject &msg, const callBackFun &fun)
{
    QString strTransation = doSendMsg(msg);
    m_msgCallBacks[strTransation] = fun;
}

void Signaling::setSeeionID(const qint64 &id)
{
    m_seeionID = id;
}

void Signaling::setEventCallBack(const QString &strName, const callBackFun &func)
{
    m_eventCallBacks[strName] = func;
}

void Signaling::setNotifyCallBack(const QString &strName, const callBackFun &func)
{
    m_notifyCallBacks[strName] = func;
}

void Signaling::slotConnected()
{
    qDebug() << __func__;
    // 这里暂时只做转发处理
    Q_EMIT sigConnected();

}

void Signaling::slotDisConnected()
{
    qDebug() << __func__;
}

void Signaling::slotError(QAbstractSocket::SocketError error)
{
    qDebug() << __func__ << error;
}

void Signaling::slotTextMessageReceived(const QString &message)
{
    QJsonObject jsonMsg = PublicFunHelper::convertToJson(message);
    qDebug() << __func__ << jsonMsg;

    if(jsonMsg.isEmpty())
    {
        return;
    }

    QString janus = jsonMsg.value(KEY_JANUS).toString();
    if (janus == "webrtcup" || janus == "media" || janus == "hangup")
    {
        if(m_notifyCallBacks.contains(janus))
        {
            callBackFun fun = m_notifyCallBacks.value(janus);
            fun(jsonMsg);
        }
    }
    else if (janus == "event")
    {
        QJsonObject plugindataOjb = jsonMsg.value(KEY_PLUGINDATA).toObject();
        QJsonObject dataObj = plugindataOjb.value(KEY_DATA).toObject();
        QString janusEvent = dataObj.value(KEY_VIDEO_ROOM).toString();

        if(m_eventCallBacks.contains(janusEvent))
        {
            callBackFun fun = m_eventCallBacks.value(janusEvent);
            fun(jsonMsg);
        }
    }
    else if (janus == "ack" || janus == "success")
    {
        QJsonObject dataObj = jsonMsg.value(KEY_DATA).toObject();
        QString transaction = jsonMsg.value(KEY_TRANSACTION).toString();
        if(m_msgCallBacks.contains(transaction))
        {
            callBackFun fun = m_msgCallBacks.value(transaction);
            m_msgCallBacks.remove(transaction);
            fun(dataObj);
        }
    }
}
